package com.east.config.filters;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.east.entity.User;
import com.east.result.Result;
import com.east.utils.CodeEnum;
import com.east.utils.Constants;
import com.east.utils.JWTUtils;
import com.east.utils.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;


import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Component
public class TokenFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;



    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 0. 放行登陆请求
        if (Constants.LOGIN_URI.equals(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }
        // 1.获取token
        String jwt = request.getHeader(Constants.TOKEN_NAME);
        if("/api/customer/all2excel".equals(request.getRequestURI())){
            jwt = request.getParameter("token");
        }
        if (StrUtil.isBlank(jwt)) {
            String resStr = JSONUtil.toJsonStr(Result.FAIL(CodeEnum.LOGIN_JWT_IS_EMPTY));
            ResponseUtils.write(response, resStr);
            return;
        }
        // 2. 验证token 是否正确
        if (!JWTUtils.verifyJWT(jwt)) {
            String resStr = JSONUtil.toJsonStr(Result.FAIL(CodeEnum.LOGIN_JWT_IS_ILLEGAL));
            ResponseUtils.write(response, resStr);
            return;
        }
        // 3. 获取token中存储的用户信息
        User user = JSONUtil.toBean(JWTUtils.parseJWT(jwt), User.class);
        // 4. 判断用户信息是否存在
        if (Objects.isNull(user)) {
            String resStr = JSONUtil.toJsonStr(Result.FAIL(CodeEnum.LOGIN_JWT_IS_EXPIRE));
            ResponseUtils.write(response, resStr);
            return;
        }
        // 5. 根据用户id得到redis中的jwt
        String jwtInRedis = stringRedisTemplate.opsForValue().get(Constants.REDIS_JWT_KEY + user.getId().toString());
        // 6. 比较前端传过来的和redis中的jwt是否一致
        if (!jwt.equals(jwtInRedis)) {
            String resStr = JSONUtil.toJsonStr(Result.FAIL(CodeEnum.LOGIN_JWT_NO_MATCH));
            ResponseUtils.write(response, resStr);
            return;
        }
        // 7.获取token剩余的有效期
        Long tokenExpire = stringRedisTemplate.getExpire(Constants.REDIS_JWT_KEY + user.getId().toString(), TimeUnit.MINUTES);
        if (tokenExpire.longValue() < 30L) {
            // 如果有效期小于30分钟，刷新token有效期
            stringRedisTemplate.expire(Constants.REDIS_JWT_KEY + user.getId().toString(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.MINUTES);
        }
        // 7. 放行
        // 都验证通过了，没有问题了，需要告诉spring security框架，这样spring security框架才知道该jwt是已经登录过的
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        // 下面就是filter链继续执行，执行下一个filter
        filterChain.doFilter(request, response);
    }
}
